<!---
	Copyright 2010 Edward Trudeau, Jeremy Battle
    This software is freely available under the MIT License: http://www.opensource.org/licenses/mit-license.php
    http://ayc.googlecode.com
    
--->

<cfcomponent name="FieldService" output="false" extends="_FieldService">
	
    <cfset variables.objectInstance = structNew() />
	<cfset variables.validationService = "" />
    <cfset variables.optionService = "" />
    <cfset variables.questionService = "" />

	<cffunction name="init" access="public" output="false" returntype="FieldService">
		<cfargument name="FieldDAO" type="FieldDAO" required="true" />
		<cfargument name="FieldGateway" type="FieldGateway" required="true" />
		<cfargument name="ValidationService" type="ayc.cfc.Validation.ValidationService" required="true" />
		<cfargument name="QuestionService" type="QuestionService" required="true" />
		<cfargument name="OptionService" type="OptionService" required="true" />

		<cfset super.init(arguments.FieldDAO, arguments.FieldGateway) />
        
        <cfset variables.ValidationService = arguments.ValidationService />
        <cfset variables.QuestionService = arguments.QuestionService />
        <cfset variables.OptionService = arguments.OptionService />

		<cfreturn this/>
	</cffunction>

	<cffunction name="getFieldsByPage" access="public" output="false" returntype="array">
		<cfargument name="Page" type="string" required="true" />
		<cfargument name="FieldID" type="numeric" required="false" />
		<cfargument name="ObjectName" type="string" required="false" />
		<cfargument name="FieldName" type="string" required="false" />
		<cfargument name="FieldFullName" type="string" required="false" />
		<cfargument name="FieldType" type="string" required="false" />
		<cfargument name="FieldClass" type="string" required="false" />
		<cfargument name="DataType" type="string" required="false" />
		<cfargument name="LabelText" type="string" required="false" />
		<cfargument name="LabelClass" type="string" required="false" />
		<cfargument name="PreFieldHTML" type="string" required="false" />
		<cfargument name="PostFieldHTML" type="string" required="false" />
		<cfargument name="InnerHTML" type="string" required="false" />
		<cfargument name="DataMaxLength" type="numeric" required="false" />
		<cfargument name="MinLength" type="numeric" required="false" />
		<cfargument name="DefaultsTo" type="string" required="false" />
		<cfargument name="ContentProvider" type="string" required="false" />
        <cfargument name="WhereClause" type="string" required="no" />
		<cfargument name="Required" type="boolean" required="false" />
		
		<cfset var qGetPID = "" />	
        <cfset var arguments.pageId = "" />	
        
        <cfif NOT isValid('integer', arguments.Page)>
        	<cfquery name="qGetPID" datasource="#variables.dsn#">
            	SELECT PageId FROM aycPages
                WHERE PageTitle = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.page#" />
            </cfquery>
            <cfset arguments.pageId = variables.FieldGateway.getPageIdFromTitle(arguments.page) />
        <cfelse>
        	<cfset arguments.pageId = arguments.Page />
        </cfif>
        
        <cfif NOT structKeyExists(variables.objectInstance, "p#arguments.pageId#")>
        	<cfset variables.objectInstance["p#arguments.pageId#"] = arrayNew(1) />
        	<cfset variables.objectInstance["p#arguments.pageId#"] = variables.FieldGateway.getFieldsByPage(argumentCollection=arguments) />
        </cfif>
        <cfreturn variables.objectInstance["p#arguments.pageId#"] />
        
    </cffunction>
    
    <cffunction name="insert" returntype="struct" access="public" hint="inserts a row into the corresponding table for the submitted form fields">
		<cfargument name="fields" type="array" required="yes" hint="Array of field beans" />
		
		<cfset var result = structNew() />
		<cfset var nextTable = "" />
		<cfset var columnList = "" />
        <cfset var nextCol = "" />
		<cfset var fieldName = "" />
		<cfset var columnType = "" />
		<cfset var maxLength = "" />
        <cfset var qIns = "" />
        <cfset var qInsResult = "" />
        <cfset var iii = "" />
        <cfset var jjj = "" />
        
        <cfset result.success = false />
        <cfset result.catch = "Unknown error from formUtils.insert" />
        <cfset result.query = "" />
        <cfset result.FieldID = "" /> 
        <cfset result.content = "" />
		
		<cftry>
        	<cfif NOT arrayLen(arguments.fields)>
            	<cfthrow type="BadBeanArray" />
            </cfif>
            <cfloop from="1" to="#arrayLen(arguments.fields)#" index="iii">
            	<cfif arguments.fields[iii].getFieldType() EQ "Likert">
                	<cfloop from="1" to="#arrayLen(arguments.fields[iii].getQuestions())#" index="jjj">
                    	<cfset columnList = listAppend(columnList, arguments.fields[iii].getFieldName() & "_#jjj#") />
                    </cfloop>
                <cfelseif listFindNoCase("checkbox,checkbox other", arguments.fields[iii].getFieldType())>
                	<cfloop from="1" to="#arrayLen(arguments.fields[iii].getOptions())#" index="jjj">
                    	<cfset columnList = listAppend(columnList, arguments.fields[iii].getFieldName() & "_#jjj#") />
                    </cfloop>
                    <cfif arguments.fields[iii].getFieldType() EQ "checkbox other">
                    	<cfset columnList = listAppend(columnList, arguments.fields[iii].getFieldName() & "_other") />
                    	<cfset columnList = listAppend(columnList, arguments.fields[iii].getFieldName() & "_otherVal") />
                    </cfif>
                <cfelseif arguments.fields[iii].getFieldType() EQ "radio other">
					<cfset columnList = listAppend(columnList, arguments.fields[iii].getFieldName()) />
                    <cfset columnList = listAppend(columnList, arguments.fields[iii].getFieldName() & "_otherVal") />
                <cfelse>
                	<cfset columnList = listAppend(columnList, arguments.fields[iii].getFieldName()) />
                </cfif>
            	
            </cfloop>
            
			<cftransaction>
				
					<cfquery name="qIns" datasource="#variables.dsn#" result="qInsResult">
						INSERT INTO #arguments.fields[1].getObjectName()#
							(#columnList#)
						VALUES
							(<cfloop list="#columnList#" index="nextCol">
						<cfset fieldName = listGetAt(nextCol, 1, "_") />
                        <cfset iii = findField(arguments.fields, fieldName) />
                        <cfif iii EQ 0>
                        	<cfthrow type="FieldNotFound" message="#fieldName# not found in array; derived from column #nextCol#" />
                        </cfif>
						<cfset columnType = arguments.fields[iii].getDataType() />
						<cfset maxLength = arguments.fields[iii].getDataMaxLength() />

						<cfif len(trim(form["#nextCol#"]))>
                        	<cfif len(nextCol) GT 9 AND right(nextCol, 9) EQ "otherVal">
                            	<cfqueryparam 
                                      cfsqltype="varchar"
                                      maxlength="100"
                                      value="#trim(form['#nextCol#'])#" 
                                      null="no" />
                            <cfelse>
                            	<cfif isValid("integer", maxLength) AND listFindNoCase('varchar,nvarchar,text,ntext', columntype)>
                                    <cfqueryparam 
                                      cfsqltype="#getSQLTypeFromProp(columnType)#" 
                                      maxlength="#maxLength#" 
                                      value="#trim(form['#nextCol#'])#" 
                                      null="no" />
                                <cfelse>
                                    <cfqueryparam 
                                      cfsqltype="#getSQLTypeFromProp(columnType)#"
                                      value="#trim(form['#nextCol#'])#" 
                                      null="no" />
                                </cfif>
                            </cfif>
							
						<cfelse>
							<cfqueryparam cfsqltype="#getSQLTypeFromProp(columnType)#" value="" null="yes" />
						</cfif><cfif listFindNoCase(columnList, nextCol) NEQ listLen(columnList)>, </cfif>
							</cfloop>)
					</cfquery>
                    <cfset result.FieldID = qInsResult.IDENTITYCOL />
       				<cfset result.query = qInsResult.Sql />

			</cftransaction>
			
			<cfcatch type="database">
				<cfset result.catch = "#cfcatch.Message# & #cfcatch.Detail#" />
                <cfreturn result />
			</cfcatch>
            <cfcatch type="BadMetaDataArray">
            	<cfset result.catch = cfcatch.Message />
                <cfreturn result />
            </cfcatch>
            <cfcatch type="FieldNotFound">
            	<cfset result.catch = cfcatch.Message />
                <cfreturn result />
            </cfcatch>
            <cfcatch type="any">
            	<cfset result.catch = cfcatch.Message />
                <cfset result.content = columnList />
                <cfreturn result />
            </cfcatch>
		</cftry>
        
        <cfset result.success = true />
        
        <cfreturn result />
		
	</cffunction>
    
    <cffunction name="findField" access="private" hint="Finds the index in the field meta array that has the corresponding attribute" returntype="numeric">
    	<cfargument name="fields" type="array" required="yes" hint="The array of field beans" />
        <cfargument name="fieldName" type="string" required="yes" hint="The name of the field to find" />
        
        <cfset var iii = "" />
        
        <cfloop from="1" to="#arrayLen(arguments.fields)#" index="iii">
        	<cfif arguments.fields[iii].getFieldName() EQ arguments.fieldName>
            	<cfreturn iii />
            </cfif>
        </cfloop>
        
        <cfreturn 0 />
    </cffunction>
    
    <cffunction name="getSQLTypeFromProp" access="private" hint="I return the correct sql type for a given property data type" returntype="string">
		<cfargument name="dataType" type="string" required="yes" hint="I am the data type as stored with the property" />
		
		<cfswitch expression="#arguments.dataType#">
			<cfcase value="int">
				<cfreturn "cf_sql_integer" />
			</cfcase>
			<cfcase value="tinyint">
				<cfreturn "CF_SQL_TINYINT" />
			</cfcase>
			<cfcase value="smallint">
				<cfreturn "CF_SQL_SMALLINT" />
			</cfcase>
			<cfcase value="bit">
				<cfreturn "CF_SQL_BIT" />
			</cfcase>
			<cfcase value="varchar,nvarchar">
				<cfreturn "CF_SQL_VARCHAR" />
			</cfcase>
			<cfcase value="text,ntext">
				<cfreturn "CF_SQL_LONGVARCHAR" />
			</cfcase>
			<cfcase value="datetime">
				<cfreturn "CF_SQL_TIMESTAMP" />
			</cfcase>
			<cfcase value="date">
				<cfreturn "CF_SQL_DATE" />
			</cfcase>
			<cfcase value="float">
				<cfreturn "CF_SQL_FLOAT" />
			</cfcase>
			<cfcase value="blob">
				<cfreturn "CF_SQL_BLOB" />
			</cfcase>
			<cfdefaultcase>
				<cfreturn "CF_SQL_CHAR" />
			</cfdefaultcase>
		
		</cfswitch>
	</cffunction>
    
    <cffunction name="getGateway" access="public" output="false" returntype="FieldGateway">
    	<cfreturn variables.FieldGateway />
    </cffunction>
    
    <cffunction name="getDAO" access="public" output="false" returntype="FieldDAO">
    	<cfreturn variables.FieldDAO />
    </cffunction>
</cfcomponent>


